package cz.data.platform.web;

import ch.qos.logback.classic.Level;
import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import com.github.xiaoymin.knife4j.spring.extension.OpenApiExtensionResolver;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.cloud.commons.util.InetUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
import org.springframework.util.ClassUtils;
import org.springframework.web.bind.annotation.RequestMethod;
import springfox.documentation.RequestHandler;
import springfox.documentation.builders.*;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.spring.web.readers.operation.CachingOperationNameGenerator;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Slf4j
@EnableKnife4j
@EnableSwagger2WebMvc
@AutoConfigureOrder(3)
public class SwaggerAutoConfiguration {

    @Autowired
    private InetUtils inetUtils;
    @Autowired
    private Environment environment;
    @Resource
    OpenApiExtensionResolver openApiExtensionResolver;

    @Bean
    public Docket createRestApi() {
        ch.qos.logback.classic.Logger logger = (ch.qos.logback.classic.Logger) log;
        logger.getLoggerContext().getLogger(CachingOperationNameGenerator.class).setLevel(Level.WARN);
        log.info("载入swagger文档配置");
        return new Docket(DocumentationType.SWAGGER_2)
                //通过调用自定义方法apiInfo，获得文档的主要信息
                .apiInfo(apiInfo())
                //设置全局参数
                .globalOperationParameters(globalParamBuilder())
                //设置全局响应参数
                .globalResponseMessage(RequestMethod.GET, responseBuilder())
                .globalResponseMessage(RequestMethod.POST, responseBuilder())
                .globalResponseMessage(RequestMethod.PUT, responseBuilder())
                .globalResponseMessage(RequestMethod.DELETE, responseBuilder())
                .groupName("v1")
                .select()
                //扫描该包下面的API注解
                .apis(this::basePackage)
                .paths(PathSelectors.any())
                .build()
                .extensions(openApiExtensionResolver.buildExtensions("v1"))
                //设置安全认证
                .securitySchemes(security());
    }

    private boolean basePackage(RequestHandler requestHandler) {
        return Optional.of(requestHandler.declaringClass())
                .map(ClassUtils::getPackageName)
                .map(packageName -> packageName.endsWith("controller"))
                .orElse(false);
    }

    private ApiInfo apiInfo() {
        String applicationName = environment.getProperty("spring.application.name");
        String version = environment.getProperty("app.version", "v1");
        String ipAddress = this.inetUtils.findFirstNonLoopbackHostInfo().getIpAddress();
        String serverPort = environment.getProperty("server.port");
        return new ApiInfoBuilder()
                .title(applicationName)
                .description(String.format("%s 接口文档", applicationName))
                .termsOfServiceUrl(String.format("http://%s:%s/doc.html", ipAddress, serverPort))
                .version(version)
                .contact(new Contact("Aaron_Xie", "http://www.baidu.com", "xzh_dev@163.com"))
                .build();
    }

    private List<ApiKey> security() {
        List<ApiKey> apiKeys = new ArrayList<>();
        apiKeys.add(new ApiKey("Authorization", "Authorization", "header"));
        return apiKeys;
    }

    private List<Parameter> globalParamBuilder() {
        List<Parameter> pars = new ArrayList<>();
        pars.add(parameterBuilder("Authorization", "令牌", "string", "header", false).build());
        return pars;
    }

    private ParameterBuilder parameterBuilder(String name, String desc, String type, String parameterType, boolean required) {
        ParameterBuilder tokenPar = new ParameterBuilder();
        tokenPar.name(name).description(desc).modelRef(new ModelRef(type)).parameterType(parameterType).required(required).build();
        return tokenPar;
    }

    private List<ResponseMessage> responseBuilder() {
        List<ResponseMessage> responseMessageList = new ArrayList<>();
        responseMessageList.add(new ResponseMessageBuilder().code(200).message("响应成功").build());
        responseMessageList.add(new ResponseMessageBuilder().code(500).message("服务器内部错误").build());
        return responseMessageList;
    }
}
